chore(ci): modernize Node matrix — drop EOL versions, target Active LTS + Current - #17
Merged
AlbSar merged 1 commit intoMay 20, 2026
Conversation
…TS + Current Sprint 175 PR #16 CI dogfood surfaced 230+ test failures across the entire matrix. Root cause was not Sprint 175 work — it was systemic CI rot. ## Why now | Node | Status (May 2026) | We were testing? | |------|---------------------|---------------------| | v18 (Hydrogen) | EOL Apr 2025 — 1+ year dead | ❌ Yes (wasted) | | v20 (Iron) | EOL Mar 2026 — 2 months dead | ❌ Yes (wasted) | | v22 (Jod) | Maintenance EOL May 2026 — this month | ❌ Yes (wasted) | | **v24 (Krypton)** | **Active LTS (until May 2027) — production target** | ❌ NO (untested) | | v26 | Current (latest) | ❌ NO (untested) | The matrix burned three slots on dead-or-dying releases while never touching Active LTS or Current. better-sqlite3 v12.10.0 (released May 12, 2026) explicitly removed Node 20/23 prebuilds and added Node 26 — so the old matrix was guaranteed to fail post-12.10.0 anyway. ## Changes - All 7 workflows (`ci.yml`, `dashboard-build.yml`, `cross-platform-e2e.yml`, `docs.yml`, `publish.yml`, `release.yml`, `secret-scan.yml`): - Matrix `[18.x, 20.x, 22.x]` → `[24.x, 26.x]` (test-core, test-orchestra, test-cli, test-remaining, dashboard build) - Fixed `'22.x'` / `'20'` → `'24.x'` / `'24'` (typecheck, security, test-docs-scripts, test-dashboard, test-windows, coverage, build, docs, publish, release, secret-scan, cross-platform-e2e) - Dashboard artifact upload condition: `matrix.node-version == '22.x'` → `'24.x'` so the LTS run ships the artifact. - `package.json`: - `engines.node`: `>=18.0.0` → `>=24.0.0`. Breaking-change-by-design for OSS GA — Node 18/20/22 users get a clear error instead of a runtime crash later (npm shows `engineStrict` warning at install time). - `better-sqlite3`: `^12.9.0` → `^12.10.0` (Node 26 prebuilds, Node 20/23 cleanup). Verified locally: 12.10.0 ships prebuilds for the new matrix; no native compile required at install time. - New script `ci:rebuild-native: npm rebuild better-sqlite3 --ignore- scripts=false`. Required because `.npmrc` sets `ignore-scripts=true` (Sprint 167 H3 supply-chain hardening); `npm ci` honours that and skips better-sqlite3's `prebuild-install || node-gyp rebuild`, so the native binding never lands without an explicit rebuild step. Targeted to the one package that needs it — the .npmrc guard for every other dependency stays intact. - All 7 workflows: new step `npm run ci:rebuild-native` after `npm ci`. Five-second cost per job; without it the binding is missing and 200+ tests collapse on `Database` instantiation. - `src/cli/entry.ts`: runtime Node guard `< 18` → `< 24`. Error message updated to mention Active LTS. - 7 test files realigned: - `tests/github/ci-workflow.test.ts`, `tests/github/workflows/ci.test.ts`, `tests/github/workflows/release.test.ts` — workflow assertions against the new matrix and fixed versions. - `tests/cli/bin-entry-validation.test.ts`, `tests/cli/npx-compat.test.ts` — engines.node and entry.ts guard assertions. - `tests/core/nervous-enabled-integration.test.ts` — `.deckent/config. json` dogfood-only assertion now skipped when the file is absent (PR #16 made the config gitignored). ## Local verification (Node 24.15.0, the current Active LTS) | Gate | Result | |------|--------| | Non-orchestra suites | 475 files, **10,625 pass**, 23 skip, **0 fail** | | Orchestra suite | 205 files, **4,416 pass**, 11 skip, **0 fail** | | Dashboard suite | 23 files, **493 pass**, **0 fail** | | `tsc --noEmit` | clean | | `npm run build` | dist/cli/{index,entry}.js, dist/mcp/server.js, dist/index.js all present with shebang | | VitePress build | complete | | `secret-baseline.mjs` | 0 unallowlisted secrets | Total: **15,534 tests pass, 0 fail**. ## Baseline note This PR is based on `docs/embedded-web-terminal-spec` (PR #16). PR #16's test/vitepress/secret-baseline fixes are inherited; once PR #16 merges to main, this PR's base becomes main automatically with no conflict. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Drop Node 18/20/22, add Node 24 + 26. Bump engines, fix better-sqlite3 native binding install, realign 7 dogfood test files. Local: 15,534 tests pass, 0 fail.
Base =
docs/embedded-web-terminal-spec(PR #16) so PR #16's test/vitepress/secret-baseline fixes are inherited. Auto-converts to base=main once PR #16 merges.Why this PR exists
Sprint 175 PR #16 CI dogfood produced 230+ test failures across the entire matrix. Root cause was not Sprint 175 work — it was systemic CI rot.
The matrix burned three slots on dead-or-dying releases and never touched Active LTS or Current.
better-sqlite3@12.10.0(May 12 2026 — eight days ago) explicitly removed Node 20/23 prebuilds and added Node 26, so the old matrix was guaranteed to fail post-12.10.0 regardless.What changed
Workflow matrix bump (all 7 yml files)
[18.x, 20.x, 22.x]→[24.x, 26.x]across test-core, test-orchestra, test-cli, test-remaining, dashboard build.'22.x'/'20'→'24.x'/'24'across typecheck, security, test-docs-scripts, test-dashboard, test-windows, coverage, build, docs, publish, release, secret-scan, cross-platform-e2e.matrix.node-version == '22.x'→'24.x'so the LTS run ships the artifact.package.json
engines.node:>=18.0.0→>=24.0.0. Breaking change by design — Node 18/20/22 users see a clear error atnpm installtime (engineStrict warning) instead of a runtime crash later.better-sqlite3:^12.9.0→^12.10.0(Node 26 prebuilds added, Node 20/23 cleanup).ci:rebuild-native: npm rebuild better-sqlite3 --ignore-scripts=false. Required because the project's.npmrcsetsignore-scripts=true(Sprint 167 H3 supply-chain hardening);npm cihonours that and skips better-sqlite3's install script, so the native binding never lands without an explicit rebuild. Targeted to the one native dep that needs it.Workflows: new step
npm run ci:rebuild-nativeafter everynpm ci~5-second cost per job. Without it the binding is missing and 200+ tests collapse on
Databaseinstantiation.Runtime guard (
src/cli/entry.ts)< 18→< 24. Error message updated to mention Active LTS.Test realignments (7 files)
tests/github/ci-workflow.test.ts,tests/github/workflows/ci.test.ts,tests/github/workflows/release.test.ts— workflow assertions against the new matrix and fixed versions.tests/cli/bin-entry-validation.test.ts,tests/cli/npx-compat.test.ts— engines.node and entry.ts guard assertions.tests/core/nervous-enabled-integration.test.ts—.deckent/config.jsondogfood assertion now skipped when the file is absent (PR feat(terminal): embedded web terminal — sub-project #1/4 (spec→plan→Sprint 175) #16 made the config gitignored).Local verification (Node 24.15.0)
tsc --noEmitnpm run buildsecret-baseline.mjsTotal: 15,534 tests pass, 0 fail locally.
Expected CI delta
Databaseerrors).Test plan
npm installclean on Node 24npm run buildproduces all expected binariesdeckent --versionon Node 24 + Node 26🤖 Generated with Claude Code